'use strict';

var expect = require('expect.js')
var wickrcrypto = require('../../../../../node/lib/wickrcrypto')

describe("Wickr Crypto Engine", function() {

    it("should generate random bytes", function() {
        var testData = wickrcrypto.CryptoEngine.randomBytes(32)
        expect(testData).to.be.a('object')
        expect(testData.byteLength).to.eql(32)

        var hasMatch = false

        for (var i = 0; i <= 1000; i++) {
            var anotherData = wickrcrypto.CryptoEngine.randomBytes(32)
            if (anotherData == testData) {
                hasMatch = true
                break
            }
         } 

         expect(hasMatch).to.eql(false)
    });

    it("performs cipher / decipher", function(){

        var rndData =wickrcrypto.CryptoEngine.randomBytes(32)
        var key =wickrcrypto.CipherKey.fromComponents(wickrcrypto.Cipher.aes256Gcm(), rndData)

        expect(key).to.be.a("object")
        expect(key.keyData).to.eql(rndData)

        key =wickrcrypto.CryptoEngine.randomKey(wickrcrypto.Cipher.aes256Gcm())
        expect(key).to.be.a("object")

        var testValue = Buffer.from("Helloworld")

        //Perform AES Cipher, NULL param means generate random IV
        var ciphered = wickrcrypto.CryptoEngine.cipher(testValue, null, key, null)
        expect(ciphered).to.be.a("object")

        //Keys are objects, you need to serialize them to bytes to store in db, send over network etc
        var serializedKey = key.serialize()
        expect(serializedKey).to.be.a("object")

        //Cipher results are objects, you need to serialize them to bytes to store in db, send over network etc
        var serializedCipherResult = ciphered.serialize()
        expect(serializedCipherResult).to.be.a("object")

        //To import a serialized key /  result into an object the from buffer method is used
        var deserializedKey = wickrcrypto.CipherKey.fromBuffer(serializedKey)
        expect(deserializedKey).to.be.a("object")

        var deserializedCipherResult = wickrcrypto.CipherResult.fromBuffer(serializedCipherResult)
        expect(deserializedCipherResult).to.be.a("object")

        //The decipher method returns the deciphered data directly
        var deciphered = wickrcrypto.CryptoEngine.decipher(deserializedCipherResult, null, deserializedKey, true)

        expect(deciphered).be.a("object")
        expect(deciphered).to.eql(testValue)

    });

    it("signs / verifies", function() {
        //Generate a random EC Key
        var testECKey = wickrcrypto.CryptoEngine.randEcKey(wickrcrypto.ECCurve.p521())

        expect(testECKey).to.be.a("object")

        var testPrivateKeyData = testECKey.priData
        var testPubKeyData = testECKey.pubData

        // Import a buffer into an EC Key object (true means private, false means public)
        var restoreTestKeyPrivate = wickrcrypto.CryptoEngine.importEcKey(testPrivateKeyData, true)
        var restoreTestKeyPublic = wickrcrypto.CryptoEngine.importEcKey(testPubKeyData, false)

        expect(restoreTestKeyPrivate).to.be.a("object")
        expect(restoreTestKeyPublic).to.be.a("object")

        var testData = Buffer.from("Helloworld")

        // Generate a signature using a private ec key, data, and a hashing method
        var testSignature = wickrcrypto.CryptoEngine.ecSign(restoreTestKeyPrivate, testData, wickrcrypto.Digest.sha512())
        
        expect(testSignature).to.be.a("object")

        // The test signature is an object, so we must serialize it into bytes for storage and network
        var testSignatureData = testSignature.serialize()

        expect(testSignatureData).be.a("object")

        // Create a signature result from a buffer generated by serialize
        var testSignatureRestore = wickrcrypto.ECDSAResult.createFromBuffer(testSignatureData)

        expect(testSignatureRestore).to.be.a("object")

        // Verify a signature where testData is the expected data, restoreTestKeyPublic is the public key
        // and testSignatureRestore is a signature object
        var isValid = wickrcrypto.CryptoEngine.ecVerify(testSignatureRestore, restoreTestKeyPublic, testData)

        expect(isValid).to.eql(true)

        var anotherECKey = wickrcrypto.CryptoEngine.randEcKey(wickrcrypto.ECCurve.p521())
        expect(anotherECKey).to.be.a("object")

        isValid = wickrcrypto.CryptoEngine.ecVerify(testSignatureRestore, anotherECKey, testData)

        expect(isValid).to.eql(false)
    });

    it("hashes", function() {
        // Generate a hash
        var hash256Salt = wickrcrypto.CryptoEngine.digest(Buffer.from("Hello"), Buffer.from("world"), wickrcrypto.Digest.sha256())
        var hash256NoSalt = wickrcrypto.CryptoEngine.digest(Buffer.from("Helloworld"), null, wickrcrypto.Digest.sha256())

        expect(hash256Salt).to.be.a("object")
        expect(hash256NoSalt).to.be.a("object")

        expect(hash256Salt).to.eql(hash256NoSalt)

        var saltHex = hash256Salt.toString('hex')
        var nosaltHex = hash256NoSalt.toString('hex')

        expect(saltHex).to.eql(nosaltHex)
    });

    it("performs ecdh", function() {
        // Do an export / import to delete the private side of the key to ensure a proper test
        var theirKey = wickrcrypto.CryptoEngine.randEcKey(wickrcrypto.ECCurve.p521())
        var ourKey = wickrcrypto.CryptoEngine.randEcKey(wickrcrypto.ECCurve.p521())

        expect(theirKey).to.be.a("object")
        expect(ourKey).to.be.a("object")

        var outputSecret = wickrcrypto.CryptoEngine.ecdhGenSharedSecret(ourKey, theirKey)

        expect(outputSecret).to.be.a("object")

        ourKey = wickrcrypto.CryptoEngine.randEcKey(wickrcrypto.ECCurve.p521())

        var outputSecret2 = wickrcrypto.CryptoEngine.ecdhGenSharedSecret(ourKey, theirKey)
        expect(outputSecret2).to.be.a("object")

        expect(outputSecret).to.not.eql(outputSecret2)
    });

    it("performs scrypt", function(){
        this.timeout(6000);
        var passphrase = Buffer.from("password")

        var kdf = wickrcrypto.CryptoEngine.kdf(wickrcrypto.KDFAlgo.scrypt17(), passphrase)
        expect(kdf).to.be.a("object")
    });

    it("performs bcrypt", function(){
        this.timeout(15000);
        var passphrase = Buffer.from("password")
        var bcrypt = wickrcrypto.CryptoEngine.kdf(wickrcrypto.KDFAlgo.bcrypt15(), passphrase)
        expect(bcrypt).to.be.a("object")
    });

    it("performs kdf crypto", function() {
        this.timeout(10000);
        var passphrase = Buffer.from("password")
        var testValue = Buffer.from("Helloworld")

        var ciphered = wickrcrypto.CryptoEngine.kdfEncrypt(wickrcrypto.KDFAlgo.scrypt17(), wickrcrypto.Cipher.aes256Gcm(), testValue, passphrase)
        expect(ciphered).to.be.a("object")

        var decipheredInvalidPass = wickrcrypto.CryptoEngine.kdfDecrypt(ciphered, Buffer.from("invalid password"))
        expect(decipheredInvalidPass).to.not.be.a("object")

        var deciphered = wickrcrypto.CryptoEngine.kdfDecrypt(ciphered, passphrase)
        expect(deciphered).to.eql(testValue)

    });

});
